#pragma once
#include "../basic/basic_types.h"
#include <Windows.h>
#include <optional>
#include <string>

/** 内存搜索 **/

// 因为要映射 ?? 所以用 short 宽度, 返回字节数组长度(字节数)
size_t string_to_bytes(IN std::string sign, IN OUT short *dest);

/// @brief 比较特征码和指定缓存中的字节是否一致
///		先去掉字符串空格, 然后循环, 每两个字符转换为一个字节. 如果是 ??
/// 那么这个字节总是匹配的, 也不需要转换为字节.
/// @param sign 类似 49 8B 40 08 48 C1 E8 3A 84 C0 74 ?? 41 0F 10 00
/// @param buf 指定缓存
/// @return 如果匹配返回 true, 如果不匹配 返回 false.
bool cmp_sign(short *sign, byte *buf, size_t len);
std::optional<std::pair<uint64, uint64>> get_module_addrs(uint32 pid);
std::optional<uint64> get_module_base(uint32 pid);

// 获取内存地址(大部分时候用于 call 内定位 call 地址)
uint64 scan_raw_addr(HANDLE process, uint64 start, uint64 end, std::string sign,
                     int line_offset);
// 调用上面的, 返回 rva 或 0;
uint64 scan_raw_addr_rva(HANDLE process, uint64 start, uint64 end,
                         std::string sign, int line_offset);
uint64 scan_raw(HANDLE process, uint64 start, uint64 end, std::string sign,
                int line_offset, uint32 inline_offset, uint32 cmd_len);
// 扫描 call. 调用 ScanRaw, inlineOffset 固定是 1, cmdSize 固定是 4, 返回 rva
uint64 scan_call(HANDLE process, uint64 start, uint64 end, std::string sign,
                 int line_offset /*, uint32 inlineOffset, uint32 cmdSize*/);
// 扫描基址, 调用 ScanRaw, cmdSize 是固定 4 的, 返回 rva
uint64 scan_base(HANDLE process, uint64 start, uint64 end, std::string sign,
                 int line_offset, uint32 inline_offset /*, uint32 cmdSize*/);
uint64 scan_offset(HANDLE process, uint64 start, uint64 end, std::string sign,
                   int line_offset, uint32 inline_offset, uint32 cmd_len);
// 比较特殊的情况, 基址不好定位, 但是所在的 call 比较好定位, 通过 call
// 的特征码定位到 call 再定位到基址.
uint64 scan_base_in_call(HANDLE process, uint64 start, uint64 end,
                         std::string sign, int line_offset,
                         uint32 call_line_offset, uint32 call_inline_offset);
